package ChannelTutorial.Demo02;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

/**
 * Demo02 - ChannelFuture 异步操作详解 - 客户端
 * 
 * 学习目标：
 * 1. 理解 Netty 的异步模型
 * 2. 掌握 ChannelFuture 的使用方法
 * 3. 学习添加监听器处理异步结果
 * 4. 了解 sync() 和 await() 的区别
 * 5. 掌握异步操作的最佳实践
 */
@Slf4j
public class Client {

    public static void main(String[] args) throws Exception {
        log.info("=== ChannelFuture 异步操作演示 - 客户端 ===\n");
        log.info("请先启动 Server.java，然后运行本客户端\n");
        
        // 演示各种 ChannelFuture 的使用方式
        demo1_BasicFuture();
        demo2_AddListener();
        demo3_SyncVsAwait();
        demo4_ChainListeners();
        demo5_BestPractices();
        
        // 等待一段时间后退出
        Thread.sleep(2000);
        System.exit(0);
    }

    /**
     * Demo 1: ChannelFuture 基础概念
     * 
     * 重点：
     * - Netty 的所有 I/O 操作都是异步的
     * - 操作会立即返回 ChannelFuture，不会阻塞
     * - 可以通过 ChannelFuture 查询操作状态
     */
    private static void demo1_BasicFuture() throws Exception {
        log.info("\n┌─────────────────────────────────────────");
        log.info("│ Demo 1: ChannelFuture 基础概念");
        log.info("└─────────────────────────────────────────\n");
        
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        ch.pipeline().addLast(new SimpleHandler());
                    }
                });
            
            // connect() 返回 ChannelFuture，操作是异步的
            log.info("1. 发起连接操作...");
            long startTime = System.currentTimeMillis();
            ChannelFuture connectFuture = bootstrap.connect("localhost", 9000);
            long endTime = System.currentTimeMillis();
            
            log.info("2. connect() 方法立即返回，耗时: {} ms", endTime - startTime);
            log.info("3. 此时连接可能还没建立完成！");
            log.info("4. 连接是否完成: {}", connectFuture.isDone());
            log.info("5. 连接是否成功: {}", connectFuture.isSuccess());
            
            // 等待连接完成
            connectFuture.sync();
            log.info("6. sync() 后，连接已完成");
            log.info("7. 连接是否完成: {}", connectFuture.isDone());
            log.info("8. 连接是否成功: {}", connectFuture.isSuccess());
            
            Channel channel = connectFuture.channel();
            
            // 演示写操作也是异步的
            log.info("\n9. 发送数据...");
            startTime = System.currentTimeMillis();
            ChannelFuture writeFuture = channel.writeAndFlush(
                Unpooled.copiedBuffer("Hello", StandardCharsets.UTF_8)
            );
            endTime = System.currentTimeMillis();
            
            log.info("10. writeAndFlush() 立即返回，耗时: {} ms", endTime - startTime);
            log.info("11. 写操作是否完成: {}", writeFuture.isDone());
            
            writeFuture.sync();
            log.info("12. sync() 后，写操作已完成");
            log.info("13. 写操作是否成功: {}", writeFuture.isSuccess());
            
            channel.close().sync();
        } finally {
            group.shutdownGracefully();
        }
    }

    /**
     * Demo 2: 添加监听器 (推荐方式)
     * 
     * 重点：
     * - 使用监听器是处理异步结果的推荐方式
     * - 不会阻塞线程
     * - 操作完成后自动回调
     */
    private static void demo2_AddListener() throws Exception {
        log.info("\n┌─────────────────────────────────────────");
        log.info("│ Demo 2: 添加监听器处理异步结果");
        log.info("└─────────────────────────────────────────\n");
        
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        ch.pipeline().addLast(new SimpleHandler());
                    }
                });
            
            // 方式一：使用匿名内部类
            log.info("方式一：使用匿名内部类添加监听器");
            ChannelFuture connectFuture = bootstrap.connect("localhost", 9000);
            connectFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (future.isSuccess()) {
                        log.info("✅ 连接成功！Channel: {}", future.channel());
                        
                        // 连接成功后发送数据
                        Channel channel = future.channel();
                        ChannelFuture writeFuture = channel.writeAndFlush(
                            Unpooled.copiedBuffer("使用监听器发送", StandardCharsets.UTF_8)
                        );
                        
                        // 为写操作也添加监听器
                        writeFuture.addListener(new ChannelFutureListener() {
                            @Override
                            public void operationComplete(ChannelFuture future) throws Exception {
                                if (future.isSuccess()) {
                                    log.info("✅ 数据发送成功！");
                                } else {
                                    log.error("❌ 数据发送失败：{}", future.cause().getMessage());
                                }
                            }
                        });
                        
                    } else {
                        log.error("❌ 连接失败：{}", future.cause().getMessage());
                    }
                }
            });
            
            // 方式二：使用 Lambda 表达式（Java 8+）
            log.info("\n方式二：使用 Lambda 表达式");
            ChannelFuture future2 = bootstrap.connect("localhost", 9000);
            future2.addListener((ChannelFutureListener) future -> {
                if (future.isSuccess()) {
                    log.info("✅ Lambda: 连接成功！");
                } else {
                    log.error("❌ Lambda: 连接失败");
                }
            });
            
            // 方式三：使用预定义的监听器
            log.info("\n方式三：使用预定义的监听器");
            ChannelFuture future3 = bootstrap.connect("localhost", 9000);
            Channel channel = future3.sync().channel();
            
            // CLOSE: 操作完成后关闭连接
            channel.writeAndFlush(
                Unpooled.copiedBuffer("发送后关闭", StandardCharsets.UTF_8)
            ).addListener(ChannelFutureListener.CLOSE);
            log.info("✅ 使用 CLOSE 监听器，发送完成后自动关闭连接");
            
            // CLOSE_ON_FAILURE: 失败时关闭
            // FIRE_EXCEPTION_ON_FAILURE: 失败时触发异常事件
            
            Thread.sleep(500);
            
        } finally {
            group.shutdownGracefully();
        }
    }

    /**
     * Demo 3: sync() vs await() 的区别
     * 
     * 重点：
     * - sync() 会抛出异常
     * - await() 不会抛出异常，需要手动检查
     * - 两者都会阻塞等待操作完成
     */
    private static void demo3_SyncVsAwait() throws Exception {
        log.info("\n┌─────────────────────────────────────────");
        log.info("│ Demo 3: sync() vs await() 的区别");
        log.info("└─────────────────────────────────────────\n");
        
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        ch.pipeline().addLast(new SimpleHandler());
                    }
                });
            
            // 1. 使用 sync() - 会抛出异常
            log.info("1. 使用 sync() 连接一个不存在的地址");
            try {
                ChannelFuture future = bootstrap.connect("localhost", 9999); // 不存在的端口
                future.sync(); // 会抛出异常
            } catch (Exception e) {
                log.error("❌ sync() 抛出异常: {}", e.getMessage());
            }
            
            // 2. 使用 await() - 不会抛出异常
            log.info("\n2. 使用 await() 连接一个不存在的地址");
            ChannelFuture future = bootstrap.connect("localhost", 9999);
            future.await(); // 不会抛出异常
            
            if (future.isSuccess()) {
                log.info("✅ 连接成功");
            } else {
                log.error("❌ await() 不抛出异常，需要手动检查: {}", future.cause().getMessage());
            }
            
            // 3. 带超时的 await
            log.info("\n3. 使用带超时的 await()");
            ChannelFuture future2 = bootstrap.connect("localhost", 9999);
            boolean success = future2.await(1000, TimeUnit.MILLISECONDS);
            
            if (success) {
                log.info("操作在 1 秒内完成");
            } else {
                log.warn("⚠️  操作未在 1 秒内完成");
            }
            
        } finally {
            group.shutdownGracefully();
        }
    }

    /**
     * Demo 4: 链式监听器
     * 
     * 重点：
     * - 可以为同一个 Future 添加多个监听器
     * - 监听器按添加顺序执行
     * - 适合需要多个后续操作的场景
     */
    private static void demo4_ChainListeners() throws Exception {
        log.info("\n┌─────────────────────────────────────────");
        log.info("│ Demo 4: 链式监听器");
        log.info("└─────────────────────────────────────────\n");
        
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        ch.pipeline().addLast(new SimpleHandler());
                    }
                });
            
            ChannelFuture connectFuture = bootstrap.connect("localhost", 9000);
            
            // 添加多个监听器
            connectFuture
                .addListener((ChannelFuture future) -> {
                    log.info("监听器 1: 连接完成");
                })
                .addListener((ChannelFuture future) -> {
                    log.info("监听器 2: 记录日志");
                })
                .addListener((ChannelFuture future) -> {
                    log.info("监听器 3: 发送认证信息");
                    if (future.isSuccess()) {
                        Channel channel = future.channel();
                        channel.writeAndFlush(
                            Unpooled.copiedBuffer("AUTH:user123", StandardCharsets.UTF_8)
                        );
                    }
                })
                .addListener((ChannelFuture future) -> {
                    log.info("监听器 4: 所有初始化完成");
                });
            
            connectFuture.channel().closeFuture().sync();
            
        } finally {
            group.shutdownGracefully();
        }
    }

    /**
     * Demo 5: 最佳实践
     * 
     * 展示在实际项目中如何正确使用 ChannelFuture
     */
    private static void demo5_BestPractices() throws Exception {
        log.info("\n┌─────────────────────────────────────────");
        log.info("│ Demo 5: 最佳实践");
        log.info("└─────────────────────────────────────────\n");
        
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        ch.pipeline().addLast(new SimpleHandler());
                    }
                });
            
            // 最佳实践 1: 连接建立后再发送数据
            log.info("最佳实践 1: 确保连接建立后再发送数据");
            bootstrap.connect("localhost", 9000)
                .addListener((ChannelFutureListener) future -> {
                    if (future.isSuccess()) {
                        Channel channel = future.channel();
                        channel.writeAndFlush(
                            Unpooled.copiedBuffer("连接成功后发送", StandardCharsets.UTF_8)
                        );
                    }
                });
            
            Thread.sleep(200);
            
            // 最佳实践 2: 发送完成后关闭连接
            log.info("\n最佳实践 2: 发送完成后关闭连接");
            ChannelFuture connectFuture = bootstrap.connect("localhost", 9000).sync();
            Channel channel = connectFuture.channel();
            
            channel.writeAndFlush(
                Unpooled.copiedBuffer("发送后关闭", StandardCharsets.UTF_8)
            ).addListener(ChannelFutureListener.CLOSE);
            
            Thread.sleep(200);
            
            // 最佳实践 3: 异常处理
            log.info("\n最佳实践 3: 完善的异常处理");
            bootstrap.connect("localhost", 9000)
                .addListener((ChannelFutureListener) future -> {
                    if (future.isSuccess()) {
                        log.info("✅ 连接成功");
                        Channel ch = future.channel();
                        
                        ch.writeAndFlush(
                            Unpooled.copiedBuffer("带异常处理的消息", StandardCharsets.UTF_8)
                        ).addListener((ChannelFutureListener) writeFuture -> {
                            if (writeFuture.isSuccess()) {
                                log.info("✅ 消息发送成功");
                            } else {
                                log.error("❌ 消息发送失败", writeFuture.cause());
                                ch.close(); // 发送失败，关闭连接
                            }
                        });
                        
                    } else {
                        log.error("❌ 连接失败", future.cause());
                        // 进行重连或其他处理
                    }
                });
            
            Thread.sleep(200);
            
        } finally {
            group.shutdownGracefully();
        }
    }

    /**
     * 简单的处理器
     */
    static class SimpleHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            ByteBuf buf = (ByteBuf) msg;
            log.info("[客户端] 收到回复: {}", buf.toString(StandardCharsets.UTF_8));
            buf.release();
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            ctx.close();
        }
    }
}

/*
=== 运行结果分析 ===

1. ChannelFuture 的本质：
   - 代表一个异步操作的结果
   - 操作立即返回，不会阻塞
   - 可以查询操作状态和结果

2. 处理异步结果的方式：
   ✅ 推荐：添加监听器（不阻塞）
   ⚠️  慎用：sync() 或 await()（会阻塞）

3. sync() vs await()：
   - sync()：阻塞等待，失败时抛出异常
   - await()：阻塞等待，失败不抛异常，需手动检查
   - await(timeout)：带超时的等待

4. 监听器的使用：
   - 匿名内部类
   - Lambda 表达式
   - 预定义监听器（CLOSE, CLOSE_ON_FAILURE 等）
   - 链式添加多个监听器

=== 关键知识点 ===

1. Netty 的所有 I/O 操作都是异步的
2. 使用监听器是处理异步结果的最佳实践
3. 避免在 EventLoop 线程中使用 sync() 或 await()
4. 操作完成后要正确处理成功和失败的情况
5. 善用预定义的监听器简化代码

=== 最佳实践 ===

✅ 使用监听器处理异步结果
✅ 连接成功后再发送数据
✅ 完善的异常处理
✅ 发送完成后及时关闭连接（如果需要）

❌ 不要在 EventLoop 线程中使用 sync()
❌ 不要忽略异常情况
❌ 不要在连接未建立时就发送数据
*/

